/**
************************************************************************************************************
*               Copyright(c) 2014, Realtek Semiconductor Corporation. All rights reserved.
************************************************************************************************************
* @file     mi_cmd.c
* @brief    User defined mi commands.
* @details  User command interfaces.
* @author   hector_huang
* @date     2019-1-11
* @version  v0.1
*************************************************************************************************************
*/

#include <time.h>
#include "mi_cmd.h"
#include "mible_log.h"
#include "miio_user_api.h"
//#include "lock_operation.h"
//#include "lock_manage.h"
//#include "lock_history.h"
//#include "lock_setting.h"

#include "iid.h"
#include "S_2_Lock_doEvent.h"
//#include "S_3_Door_doChange.h"
//#include "S_6_Battery_doChange.h"
//#include "S_7_Doorbell_doEvent.h"
#include "json/jsmi.h"
#include "json/fmt.h"

extern void mible_record_clear(void);
extern void user_record_clear(void);

user_cmd_parse_result_t user_cmd_send_obj(user_cmd_parse_value_t *pparse_value)
{	
	uint8_t lux[3] = {0x00, 0x00, 0x00};
	//uint8_t lux_no[4] = {0x00, 0x00, 0x00, 0x00};
	uint8_t lux_intensity[1] = {1};
    switch(pparse_value->dw_parameter[1])
    {
        case 1: // 有人移动环境光暗
            lux[1] = 0;
            miio_ble_obj_enque(0x000F, 3, lux, 0);
            break;
        case 2:// 有人移动环境光亮
            lux[1] = 1;
            miio_ble_obj_enque(0x000F, 3, lux, 0);
            break;
        case 3:// 环境光暗 只能光暗切换时触发事件
            lux_intensity[0] = 0;
            miio_ble_obj_enque(0x1018, 1, lux_intensity, 0);
            break;
        case 4:// 环境光亮
            lux_intensity[0] = 1;
            miio_ble_obj_enque(0x1018, 1, lux_intensity, 0);
            break;
    }
	
	
	
	return USER_CMD_RESULT_OK;
}


user_cmd_parse_result_t user_cmd_send_spec(user_cmd_parse_value_t *pparse_value)
{
    MI_LOG_INFO("receive send obj cmd para_count =%d\n",pparse_value->para_count);

    MI_LOG_INFO("pparse_value->dw_parameter[0]=0x%4X\n",pparse_value->dw_parameter[0]);
    MI_LOG_INFO("pparse_value->dw_parameter[1]=0x%4X\n",pparse_value->dw_parameter[1]);
    MI_LOG_INFO("pparse_value->pparameter[0]=%s",pparse_value->pparameter[0]);
    MI_LOG_INFO("pparse_value->pparameter[1]=%s",pparse_value->pparameter[1]);
    MI_LOG_INFO("pparse_value->pparameter[2]=%s",pparse_value->pparameter[2]);
    MI_LOG_INFO("pparse_value->pparameter[3]=%s",pparse_value->pparameter[3]);

    uint32_t total_len = pparse_value->dw_parameter[1];
    uint32_t first_len = pparse_value->dw_parameter[2];
    uint8_t in[20];
    if(total_len>=first_len){
        memcpy(in, &pparse_value->dw_parameter[3],sizeof(pparse_value->dw_parameter[2]));
        if (total_len-first_len>0){
            memcpy(&in[first_len], &pparse_value->dw_parameter[5],sizeof(pparse_value->dw_parameter[4]));
            if(total_len-first_len-pparse_value->dw_parameter[4]>0){
             memcpy(&in[first_len+pparse_value->dw_parameter[4]], &pparse_value->dw_parameter[7],sizeof(pparse_value->dw_parameter[6]));
            }
        }
    }

    MI_LOG_INFO("in=%s",in);

    //miio_ble_obj_enque(obj,len,&pparse_value->dw_parameter[2],0);
    //miio_ble_obj_enque(pparse_value->dw_parameter[0],pparse_value->dw_parameter[1],&pparse_value->dw_parameter[2],0);
    //miio_ble_obj_enque(pparse_value->dw_parameter[0],pparse_value->dw_parameter[1],&pparse_value->dw_parameter[2],0);
    miio_ble_obj_enque(pparse_value->dw_parameter[0],pparse_value->dw_parameter[1],&in,0);


	return USER_CMD_RESULT_OK;
}

user_cmd_parse_result_t user_cmd_list(user_cmd_parse_value_t *pparse_value)
{
	MI_LOG_INFO("receive ls\n");
    
    uint32_t did = 0;
    uint8_t byte_did[8];
    get_mi_device_id(byte_did);
    did = (byte_did[4]<<24) + (byte_did[5]<<16) + (byte_did[6]<<8) + byte_did[7];
    
    data_uart_debug("----mijia ble secure demo----\r\n");
    data_uart_debug("device id: %d\r\n", did);
    data_uart_debug("reg %d, login %d\r\n", get_mi_reg_stat(), get_mi_authorization());
    data_uart_debug("utc time: %d\r\n", time(NULL));//mible_systime_utc_get());
    
	return USER_CMD_RESULT_OK;
}

user_cmd_parse_result_t user_cmd_restore(user_cmd_parse_value_t *pparse_value)
{
	MI_LOG_INFO("receive restore\n");
    
    mible_record_clear();
    user_record_clear();
    
    miio_system_restore();

    data_uart_debug("restore done\r\n");
    
    return USER_CMD_RESULT_OK;
}

extern bool need_kbd_input;
user_cmd_parse_result_t user_cmd_input_oob(user_cmd_parse_value_t *pparse_value)
{
    if(need_kbd_input){
        need_kbd_input = false;
        MI_LOG_INFO("receive user_cmd_input_oob cnt %d\n", pparse_value->para_count);
        uint8_t oob[6] = {0};
        for(int i=0; i<6; i++)
            oob[i] = pparse_value->dw_parameter[i] + '0';
        mi_schd_oob_rsp(oob, 6);
        MI_LOG_INFO("OOB Input: %02x%02x%02x%02x%02x%02x\n", 
            oob[0], oob[1], oob[2], oob[3], oob[4], oob[5]);
    }
	
	return USER_CMD_RESULT_OK;
}

static uint16_t s_tid = 0;
//extern mible_status_t mible_handle_set_properties(uint8_t *pdata, uint16_t ilen, uint16_t tid);
//extern mible_status_t mible_handle_get_properties(uint8_t *pdata, uint16_t ilen, uint16_t tid);
//extern mible_status_t mible_handle_action(uint8_t *pdata, uint16_t ilen, uint16_t tid);
extern void spec_data_parse(uint8_t *pdata, uint16_t ilen);
user_cmd_parse_result_t user_cmd_gatt_set(user_cmd_parse_value_t *pparse_value)
{
    uint8_t data[32] = {0};
    
    uint16_t ilen = (pparse_value->para_count > USER_CMD_MAX_PARAMETERS)? USER_CMD_MAX_PARAMETERS : pparse_value->para_count;
    s_tid++;
    
    //header
    data[0] = ilen + 5;
    data[1] = 0x20;
    //tid
    data[2] = s_tid & 0xff;
    data[3] = (s_tid>>8) & 0xff;
    //opcode
    data[4] = MIBLE_GATT_SPEC_OP_SET_PROPERTY;
    
    for(int i=0; i<ilen; i++){
        data[i+5] = pparse_value->dw_parameter[i];
    }
    
    MI_LOG_INFO("receive user_cmd_gatt_set tid %d, len %d, rawdata:\n", s_tid, ilen);
    MI_LOG_HEXDUMP(data, ilen+5);
    //mible_handle_set_properties(data, ilen, s_tid);
    spec_data_parse(data, ilen+5);
    
    data_uart_debug("spec_data_parse: len %d\r\n", ilen);
    data_uart_dump(data, ilen+5);
    
	return USER_CMD_RESULT_OK;
}

user_cmd_parse_result_t user_cmd_gatt_get(user_cmd_parse_value_t *pparse_value)
{
    uint8_t data[32] = {0};
    
    uint16_t ilen = (pparse_value->para_count > USER_CMD_MAX_PARAMETERS)? USER_CMD_MAX_PARAMETERS : pparse_value->para_count;
    s_tid++;
    
    //header
    data[0] = ilen + 5;
    data[1] = 0x20;
    //tid
    data[2] = s_tid & 0xff;
    data[3] = (s_tid>>8) & 0xff;
    //opcode
    data[4] = MIBLE_GATT_SPEC_OP_GET_PROPERTY;
    
    for(int i=0; i<ilen; i++){
        data[i+5] = pparse_value->dw_parameter[i];
    }
    
    MI_LOG_INFO("receive user_cmd_gatt_get tid %d, len %d, rawdata:\n", s_tid, ilen);
    MI_LOG_HEXDUMP(data, ilen+5);
    //mible_handle_get_properties(data, ilen, s_tid);
    spec_data_parse(data, ilen+5);
    
    data_uart_debug("spec_data_parse: len %d\r\n", ilen);
    data_uart_dump(data, ilen+5);
    
	return USER_CMD_RESULT_OK;
}

user_cmd_parse_result_t user_cmd_gatt_action(user_cmd_parse_value_t *pparse_value)
{
	uint8_t data[32] = {0};
    
    uint16_t ilen = (pparse_value->para_count > USER_CMD_MAX_PARAMETERS)? USER_CMD_MAX_PARAMETERS : pparse_value->para_count;
    s_tid++;
    
    //header
    data[0] = ilen + 5;
    data[1] = 0x20;
    //tid
    data[2] = s_tid & 0xff;
    data[3] = (s_tid>>8) & 0xff;
    //opcode
    data[4] = MIBLE_GATT_SPEC_OP_ACTION;
    
    for(int i=0; i<ilen; i++){
        data[i+5] = pparse_value->dw_parameter[i];
    }
    
    MI_LOG_INFO("receive user_cmd_gatt_action tid %d, len %d, rawdata:\n", s_tid, ilen);
    MI_LOG_HEXDUMP(data, ilen+5);
    //mible_handle_action(data, ilen, s_tid);
    spec_data_parse(data, ilen+5);
    
    data_uart_debug("spec_data_parse: len %d\r\n", ilen);
    data_uart_dump(data, ilen+5);
    
	return USER_CMD_RESULT_OK;
}

user_cmd_parse_result_t user_cmd_lock_event(user_cmd_parse_value_t *pparse_value)
{
    if(pparse_value->para_count < 4){
        data_uart_debug("lock_operation: err params %d\r\n", pparse_value->para_count);
        return USER_CMD_RESULT_WRONG_NUM_OF_PARAMETERS;
    }
    
    uint8_t position = pparse_value->dw_parameter[0];
    uint8_t method = pparse_value->dw_parameter[1];
    uint8_t action = pparse_value->dw_parameter[2];
    uint16_t op_id = pparse_value->dw_parameter[3];
    
    E_2_1020_Lock_Event_doEvent(position, method, action, op_id);
    
    data_uart_debug("lock_event: pos %d, method %d, action %d, id %d, utc %d\r\n",
                    position, method, action, op_id, time(NULL));
    
	MI_LOG_INFO("receive user_cmd_lock_event\n");
	return USER_CMD_RESULT_OK;
}

user_cmd_parse_result_t user_cmd_get_otp(user_cmd_parse_value_t *pparse_value)
{
	MI_LOG_INFO("receive user_cmd_get_otp\n");
    if(pparse_value->para_count < 1){
        return USER_CMD_RESULT_WRONG_NUM_OF_PARAMETERS;
    }
    uint32_t refresh_interval = pparse_value->dw_parameter[0];
    
    //xiaomi_lock.s_utc = time(NULL);//mible_systime_utc_get();
    
    mi_otp_t otp = {0};
    mi_otp_t last_otp = {0};
    get_mi_one_time_passwd(refresh_interval, time(NULL), &otp, &last_otp);
    
    data_uart_debug("one_time_passwd utc %d\r\n", (uint32_t)time(NULL));
    data_uart_debug("now %d-%d-%d-%d-%d-%d-%d-%d\r\n", otp[0]%100000000, otp[1]%100000000,
        otp[2]%100000000, otp[3]%100000000, otp[4]%100000000, otp[5]%100000000, otp[6]%100000000, otp[7]%100000000);
    data_uart_debug("last %d-%d-%d-%d-%d-%d-%d-%d\r\n",last_otp[0]%100000000, last_otp[1]%100000000, last_otp[2]%100000000,
        last_otp[3]%100000000, last_otp[4]%100000000, last_otp[5]%100000000, last_otp[6]%100000000, last_otp[7]%100000000);
    
	return USER_CMD_RESULT_OK;
}

/*----------------------------------------------------
 * command table
 * --------------------------------------------------*/
const user_cmd_table_entry_t mi_cmd_table[] =
{
    // mi cmd
    {
        "send_obj",
        "send_obj [obj_id][len]\r\n",
        "send object id\r\n",
        user_cmd_send_obj
    },
    {
        "ls",
        "ls\r\n",
        "list node state info\r\n",
        user_cmd_list
    },
    {
        "restore",
        "restore\r\n",
        "clear all records & bind\r\n",
        user_cmd_restore
    },
    {
        "send_spec",
        "send_spec [obj_id][len][len][value][len][value][len][value]\r\n",
        "send spec id\r\n",
        user_cmd_send_spec
    },
    //user cmd input OOB
    {
        "input_oob",
        "input_oob [num1] [num2] [num3] [num4] [num5] [num6]\r\n",
        "user cmd input OOB\r\n",
        user_cmd_input_oob
    },
    //gatt spec cmd simulation
    {
        "gatt_set",
        "gatt_set [num][siid][piid][value-type][value]\r\n",
        "gatt set cmd simulation\r\n",
        user_cmd_gatt_set
    },
    //gatt spec cmd simulation
    {
        "gatt_get",
        "gatt_get [num][siid][piid]<siid><piid><...>\r\n",
        "gatt get cmd simulation\r\n",
        user_cmd_gatt_get
    },
    //gatt spec cmd simulation
    {
        "gatt_action",
        "gatt_action [siid][aiid][num][piid][type][value]<piid><type><value>\r\n",
        "gatt action cmd simulation\r\n",
        user_cmd_gatt_action
    },
    //lock physical operation simulation
    {
        "lock_event",
        "lock_event [pos][method][action][id]\r\n",
        "lock physical operation simulation\r\n",
        user_cmd_lock_event
    },
    //Get one time password list(for test)
    {
        "get_otp",
        "get_otp [interval]\r\n",
        "Get one time password list\r\n",
        user_cmd_get_otp
    },
    /* MUST be at the end: */
    {
        0,
        0,
        0,
        0
    }
};

